#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
布局画布工具模块
提供LayoutCanvas的工具函数
"""

from PyQt5.QtCore import Qt, QRect, QRectF, QPoint, QPointF

class LayoutCanvasUtils:
    """布局画布工具类"""
    
    def __init__(self, canvas):
        """初始化
        
        参数:
            canvas: LayoutCanvas实例
        """
        self.canvas = canvas
    
    def parse_area_rect(self, element, parent_rect):
        """解析UnifiedAreaRect属性"""
        area_rect = None
        for prop in element.findall('Property'):
            if prop.get('Name') == 'UnifiedAreaRect':
                area_rect = prop.get('Value')
                break
        
        if not area_rect:
            return None
        
        try:
            # 解析UnifiedAreaRect格式: {{x1,y1},{x2,y2},{x3,y3},{x4,y4}}
            area_rect = area_rect.strip('{}')
            parts = area_rect.split('},{')
            
            topleft = parts[0].strip('{').split(',')
            bottomright = parts[3].strip('}').split(',')
            
            # 解析相对和绝对坐标
            x1_rel = float(topleft[0])
            x1_abs = float(topleft[1]) if len(topleft) > 1 else 0
            y1_rel = float(parts[1].split(',')[0])
            y1_abs = float(parts[1].split(',')[1]) if len(parts[1].split(',')) > 1 else 0
            
            x2_rel = float(parts[2].split(',')[0])
            x2_abs = float(parts[2].split(',')[1]) if len(parts[2].split(',')) > 1 else 0
            y2_rel = float(bottomright[0])
            y2_abs = float(bottomright[1]) if len(bottomright) > 1 else 0
            
            # 计算像素位置 - 使用浮点数计算以保持精度
            parent_width = float(parent_rect.width())
            parent_height = float(parent_rect.height())
            
            # 根据渲染模式计算坐标
            if self.canvas.final_render_mode:
                # 最终渲染模式：模拟基准分辨率拉伸到目标分辨率的效果
                base_width = float(self.canvas.base_resolution[0])
                base_height = float(self.canvas.base_resolution[1])
                
                # 获取父元素在基准分辨率下的相对位置
                parent_x_ratio = float(parent_rect.x()) / float(self.canvas.resolution[0])
                parent_y_ratio = float(parent_rect.y()) / float(self.canvas.resolution[1])
                parent_width_ratio = parent_width / float(self.canvas.resolution[0])
                parent_height_ratio = parent_height / float(self.canvas.resolution[1])
                
                # 模拟拉伸效果：基准分辨率到目标分辨率的比例
                stretch_width_ratio = float(self.canvas.resolution[0]) / base_width
                stretch_height_ratio = float(self.canvas.resolution[1]) / base_height
                
                # 计算在基准分辨率下的位置
                base_parent_x = parent_x_ratio * base_width
                base_parent_y = parent_y_ratio * base_height
                base_parent_width = parent_width_ratio * base_width
                base_parent_height = parent_height_ratio * base_height
                
                # 计算元素在基准分辨率下的位置
                base_x1 = base_parent_x + (x1_rel * base_parent_width + x1_abs)
                base_y1 = base_parent_y + (y1_rel * base_parent_height + y1_abs)
                base_x2 = base_parent_x + (x2_rel * base_parent_width + x2_abs)
                base_y2 = base_parent_y + (y2_rel * base_parent_height + y2_abs)
                
                # 模拟拉伸到目标分辨率
                x1 = base_x1 * stretch_width_ratio
                y1 = base_y1 * stretch_height_ratio
                x2 = base_x2 * stretch_width_ratio
                y2 = base_y2 * stretch_height_ratio
            else:
                # 编辑模式：按照相对于父元素的坐标计算
                x1 = float(parent_rect.x()) + (x1_rel * parent_width + x1_abs)
                y1 = float(parent_rect.y()) + (y1_rel * parent_height + y1_abs)
                x2 = float(parent_rect.x()) + (x2_rel * parent_width + x2_abs)
                y2 = float(parent_rect.y()) + (y2_rel * parent_height + y2_abs)
            
            # 使用QRectF替代QRect，避免精度损失
            return QRectF(x1, y1, x2-x1, y2-y1)
        except Exception as e:
            print(f"解析UnifiedAreaRect出错: {e}")
            return None
    
    def find_parent_element(self, element):
        """查找元素的父元素"""
        if self.canvas.root.tag == 'GUILayout':
            window = self.canvas.root.find('Window')
            if window == element:
                return None
            
            return self.find_parent_element_recursive(window, element)
        else:
            if self.canvas.root == element:
                return None
            
            return self.find_parent_element_recursive(self.canvas.root, element)
        
        return None
    
    def find_parent_element_recursive(self, parent, element):
        """递归查找父元素"""
        for child in parent.findall('Window'):
            if child == element:
                return parent
            
            result = self.find_parent_element_recursive(child, element)
            if result:
                return result
        
        return None
    
    def find_element_at_position(self, pos):
        """查找给定位置的元素"""
        if self.canvas.root.tag == 'GUILayout':
            window = self.canvas.root.find('Window')
            if window is not None:
                return self.find_element_in_subtree(window, pos, QRectF(0, 0, float(self.canvas.resolution[0]), float(self.canvas.resolution[1])))
        else:
            return self.find_element_in_subtree(self.canvas.root, pos, QRectF(0, 0, float(self.canvas.resolution[0]), float(self.canvas.resolution[1])))
        return None
    
    def find_element_in_subtree(self, element, pos, parent_rect):
        """递归查找子树中的元素
        
        支持QRectF高精度浮点矩形
        """
        # 如果元素被隐藏，则跳过
        if element in self.canvas.hidden_elements:
            return None
            
        rect = self.parse_area_rect(element, parent_rect)
        if rect is None:
            return None
        
        # 创建精确的点对象
        pos_f = QPointF(pos)
        
        # 如果已有选中元素，检查是否点击到了选中元素的调整手柄
        if self.canvas.selected_element == element:
            handle = self.get_handle_at_position(pos_f, rect)
            if handle is not None:
                # 如果点击到了手柄，直接返回选中的元素
                return element
        
        # 先检查子元素
        for child in reversed(list(element.findall('Window'))):
            # 检查子元素是否有被选中的调整手柄，如果有则优先返回
            child_rect = self.parse_area_rect(child, rect)
            if child_rect and self.canvas.selected_element == child:
                handle = self.get_handle_at_position(pos_f, child_rect)
                if handle is not None:
                    return child
                    
            found = self.find_element_in_subtree(child, pos, rect)
            if found:
                return found
        
        # 再检查当前元素
        if rect.contains(pos_f):
            return element
        
        return None
    
    def get_handle_at_position(self, pos, rect):
        """获取指定位置的调整手柄
        
        参数:
            pos: 鼠标位置
            rect: 元素矩形（QRect或QRectF）
            
        返回:
            手柄索引（0-7）或None
        """
        if not rect or not self.canvas.selected_element:
            return None
            
        # 调整手柄大小
        handle_size = self.canvas.resize_handles_size
        half_size = handle_size / 2.0
        
        # 准备手柄位置（使用QRectF保持精度）
        handles = [
            QRectF(rect.x() - half_size, rect.y() - half_size, handle_size, handle_size),                # 左上
            QRectF(rect.x() + rect.width() / 2.0 - half_size, rect.y() - half_size, handle_size, handle_size),  # 上
            QRectF(rect.x() + rect.width() - half_size, rect.y() - half_size, handle_size, handle_size),      # 右上
            QRectF(rect.x() + rect.width() - half_size, rect.y() + rect.height() / 2.0 - half_size, handle_size, handle_size),  # 右
            QRectF(rect.x() + rect.width() - half_size, rect.y() + rect.height() - half_size, handle_size, handle_size),      # 右下
            QRectF(rect.x() + rect.width() / 2.0 - half_size, rect.y() + rect.height() - half_size, handle_size, handle_size),  # 下
            QRectF(rect.x() - half_size, rect.y() + rect.height() - half_size, handle_size, handle_size),                # 左下
            QRectF(rect.x() - half_size, rect.y() + rect.height() / 2.0 - half_size, handle_size, handle_size),  # 左
        ]
        
        # 检查鼠标是否在手柄上
        for i, handle_rect in enumerate(handles):
            if handle_rect.contains(pos):
                return i
                
        return None
    
    def update_element_position_optimized(self, element, parent_rect, x, y, width, height):
        """优化的更新元素位置方法
        
        使用高精度浮点数计算，避免累积误差
        """
        # 获取原始区域矩形进行比较
        original_rect = self.parse_area_rect(element, parent_rect)
        if not original_rect:
            return
            
        # 确保所有计算都使用浮点数
        x = float(x)
        y = float(y)
        width = float(width)
        height = float(height)
        
        # 计算相对坐标 - 使用更高精度的计算，避免累积误差
        if parent_rect.width() > 0 and parent_rect.height() > 0:
            # 直接使用精确值
            x1_rel = (x - float(parent_rect.x())) / float(parent_rect.width())
            y1_rel = (y - float(parent_rect.y())) / float(parent_rect.height())
            x2_rel = (x + width - float(parent_rect.x())) / float(parent_rect.width())
            y2_rel = (y + height - float(parent_rect.y())) / float(parent_rect.height())
            
            # 记录元素原始位置和新位置，用于子元素坐标计算
            # 使用浮点数保留精度
            original_pos = (original_rect.x(), original_rect.y(), original_rect.width(), original_rect.height())
            new_pos = (x, y, width, height)
            
            # 更新当前元素的UnifiedAreaRect - 使用高精度值
            for prop in element.findall('Property'):
                if prop.get('Name') == 'UnifiedAreaRect':
                    # 格式化新的UnifiedAreaRect值，使用10位小数增加精度
                    new_value = f"{{{{{x1_rel:.10f},0}},{{{y1_rel:.10f},0}},{{{x2_rel:.10f},0}},{{{y2_rel:.10f},0}}}}"
                    prop.set('Value', new_value)
                    break
            
            # 更新所有子元素
            self.update_child_elements_position(element, parent_rect, original_pos, new_pos)
    
    def update_child_elements_position(self, parent_element, parent_rect, original_parent_pos, new_parent_pos):
        """递归更新子元素位置，使用高精度浮点数计算避免累积误差
        
        参数:
            parent_element: 父元素
            parent_rect: 父元素的父元素矩形
            original_parent_pos: 父元素原始位置 (x, y, width, height)
            new_parent_pos: 父元素新位置 (x, y, width, height)
        """
        orig_x, orig_y, orig_width, orig_height = original_parent_pos
        new_x, new_y, new_width, new_height = new_parent_pos
        
        # 确保所有值都是浮点数
        orig_x, orig_y, orig_width, orig_height = float(orig_x), float(orig_y), float(orig_width), float(orig_height)
        new_x, new_y, new_width, new_height = float(new_x), float(new_y), float(new_width), float(new_height)
        
        # 计算缩放和位移比例
        scale_x = new_width / orig_width if orig_width > 0 else 1.0
        scale_y = new_height / orig_height if orig_height > 0 else 1.0
        
        # 创建原始父矩形和新父矩形用于递归 - 使用QRectF保持浮点精度
        original_parent_rect = QRectF(orig_x, orig_y, orig_width, orig_height)
        new_parent_rect = QRectF(new_x, new_y, new_width, new_height)
        
        # 更新每个子元素
        for child in parent_element.findall('Window'):
            # 获取子元素的原始区域
            child_rect = self.parse_area_rect(child, original_parent_rect)
            if not child_rect:
                continue
                
            # 使用浮点算法计算子元素的新位置和大小，避免积累误差
            # 1. 计算子元素在父元素中的相对位置比例 - 使用更高精度
            rel_x = (float(child_rect.x()) - orig_x) / orig_width if orig_width > 0 else 0.0
            rel_y = (float(child_rect.y()) - orig_y) / orig_height if orig_height > 0 else 0.0
            rel_width = float(child_rect.width()) / orig_width if orig_width > 0 else 0.0  
            rel_height = float(child_rect.height()) / orig_height if orig_height > 0 else 0.0
            
            # 2. 根据相对位置和父元素的新尺寸计算子元素的新位置和大小 - 直接使用浮点数
            new_child_x = new_x + rel_x * new_width
            new_child_y = new_y + rel_y * new_height  
            new_child_width = rel_width * new_width
            new_child_height = rel_height * new_height
            
            # 3. 子元素的最终尺寸和位置 - 使用QRectF保持精度
            child_new_rect = QRectF(
                new_child_x, new_child_y, 
                new_child_width, new_child_height
            )
            
            # 4. 计算子元素相对于新父元素的UnifiedAreaRect坐标 - 直接计算，避免多次转换
            if new_width > 0 and new_height > 0:
                x1_rel = (new_child_x - new_x) / new_width
                y1_rel = (new_child_y - new_y) / new_height  
                x2_rel = (new_child_x + new_child_width - new_x) / new_width
                y2_rel = (new_child_y + new_child_height - new_y) / new_height
                
                # 5. 更新子元素的UnifiedAreaRect属性 - 使用10位小数提高精度
                new_value = f"{{{{{x1_rel:.10f},0}},{{{y1_rel:.10f},0}},{{{x2_rel:.10f},0}},{{{y2_rel:.10f},0}}}}"
                for prop in child.findall('Property'):
                    if prop.get('Name') == 'UnifiedAreaRect':
                        prop.set('Value', new_value)
                        break
            
            # 6. 递归处理子元素的子元素 - 使用浮点值而不是QRect的整数值
            child_original_pos = (child_rect.x(), child_rect.y(), child_rect.width(), child_rect.height())
            child_new_pos = (new_child_x, new_child_y, new_child_width, new_child_height)  # 直接使用浮点值
            
            self.update_child_elements_position(child, new_parent_rect, child_original_pos, child_new_pos)
                    
    def update_cursor_for_handle(self, handle):
        """根据调整手柄设置光标样式"""
        if handle == self.canvas.resize_handle_positions['top_left'] or handle == self.canvas.resize_handle_positions['bottom_right']:
            self.canvas.setCursor(Qt.SizeFDiagCursor)
        elif handle == self.canvas.resize_handle_positions['top_right'] or handle == self.canvas.resize_handle_positions['bottom_left']:
            self.canvas.setCursor(Qt.SizeBDiagCursor)
        elif handle == self.canvas.resize_handle_positions['top'] or handle == self.canvas.resize_handle_positions['bottom']:
            self.canvas.setCursor(Qt.SizeVerCursor)
        elif handle == self.canvas.resize_handle_positions['left'] or handle == self.canvas.resize_handle_positions['right']:
            self.canvas.setCursor(Qt.SizeHorCursor)
        else:
            self.canvas.setCursor(Qt.ArrowCursor)
    
    def parse_unified_area_rect_string(self, area_rect_string):
        """解析UnifiedAreaRect字符串，返回四个相对坐标值
        
        参数:
            area_rect_string: 格式为 "{{x1,x1_offset},{y1,y1_offset},{x2,x2_offset},{y2,y2_offset}}"
            
        返回:
            (x1, y1, x2, y2): 四个相对坐标值的元组
        """
        try:
            # 去除所有空格
            area_rect_string = area_rect_string.replace(' ', '')
            
            # 使用正则表达式解析字符串
            import re
            pattern = r"\{\{([\d\.-]+),[\d\.-]+\},\{([\d\.-]+),[\d\.-]+\},\{([\d\.-]+),[\d\.-]+\},\{([\d\.-]+),[\d\.-]+\}\}"
            match = re.match(pattern, area_rect_string)
            
            if match:
                x1 = float(match.group(1))
                y1 = float(match.group(2))
                x2 = float(match.group(3))
                y2 = float(match.group(4))
                return (x1, y1, x2, y2)
            else:
                # 如果正则匹配失败，尝试手动解析
                # 删除大括号和空格
                clean_str = area_rect_string.strip('{}')
                parts = clean_str.split('},{')
                
                if len(parts) == 4:
                    x1 = float(parts[0].strip('{').split(',')[0])
                    y1 = float(parts[1].split(',')[0])
                    x2 = float(parts[2].split(',')[0])
                    y2 = float(parts[3].split(',')[0])
                    return (x1, y1, x2, y2)
                
            # 如果无法解析，返回默认值
            print(f"无法解析UnifiedAreaRect: {area_rect_string}")
            return (0.0, 0.0, 1.0, 1.0)
        except Exception as e:
            print(f"解析UnifiedAreaRect时出错: {e}")
            return (0.0, 0.0, 1.0, 1.0)